package afk.biglog;

import java.io.*;
import java.util.*;

import afk.biglog.gui.*;

public class FileBlockIndexer
{
	@Override
	public String toString()
	{
		return "FileBlockIndexer [source=" + source + ", linesPerBlock=" + linesPerBlock + "]";
	}

	private final File source;
	private final int linesPerBlock;
	private final List<BlockListener> listener = Collections.synchronizedList(new ArrayList<BlockListener>());
	private boolean finish;
	private final int offset;
	private boolean abort;
	private final ErrorHandler errorHandler;

	public boolean isFinish()
	{
		return finish;
	}

	public void setFinish(final boolean finish)
	{
		this.finish = finish;
	}

	public FileBlockIndexer(final File source, final int linesPerBlock, final int offset, final ErrorHandler errorHandler)
	{
		super();
		this.source = source;
		this.linesPerBlock = linesPerBlock;
		this.offset = offset;
		this.errorHandler = errorHandler;
	}

	public void addBlockListener(final BlockListener blockListener)
	{
		if (!listener.contains(blockListener))
			listener.add(blockListener);
	}

	public void index() throws FileNotFoundException, IOException, InterruptedException
	{
		final RandomAccessFile accessFile = new RandomAccessFile(source, "r");
		int block = 0;
		try
		{
			accessFile.seek(offset);
			for (;;)
			{
				block++;
				if (abort)
					break;
				final long start = accessFile.getFilePointer();
				readLines(accessFile);
				final long end = accessFile.getFilePointer();
				fireNewBlock(new Block(start, end));
				if ((end == accessFile.length()) && finish)
					break;
			}
		}
		catch (final Exception e)
		{
			errorHandler.addError("While indexing " + source + "[Block #" + block + "]: ", e);
			accessFile.close();
		}
	}

	private void fireNewBlock(final Block block)
	{
		for (final BlockListener listener : this.listener)
			listener.newBlock(block);
	}

	private void readLines(final RandomAccessFile accessFile) throws IOException, InterruptedException
	{
		for (int i = 0; i < linesPerBlock; i++)
			if (!readLine(accessFile))
				return;
	}

	private boolean readLine(final RandomAccessFile accessFile) throws IOException, InterruptedException
	{
		final String line = accessFile.readLine();
		if (line != null)
			return true;

		if (finish)
			return false;

		Thread.sleep(1000);
		return readLine(accessFile);
	}

	public void abort()
	{
		abort = true;
	}
}
